import * as THREE from 'three'
import gsap from 'gsap'

export default function modifyCityMaterial(mesh) {
    mesh.material.onBeforeCompile = (shader) => {
        shader.fragmentShader = shader.fragmentShader.replace("#include <dithering_fragment>", `
            #include <dithering_fragment>
            //#end#
        `)
        // 添加渐变颜色
        addGradColor(mesh, shader)
        // 添加扩散圆圈
        addSpread(shader)
        // 添加扫描直线
        addLightLine(shader)
        // 添加向上扫描直线
        addToTopLine(shader)
    }
}

export function addGradColor(mesh, shader) {
    mesh.geometry.computeBoundingBox(); // 要获取mesh的顶点在场景的最大值和最小值，要先调用computeBoundingBox获取才会生效
    let { min, max } = mesh.geometry.boundingBox;
    // 获取物体的高度差
    let uHeight = max.y - min.y;
    shader.uniforms.uTopColor = {
        value: new THREE.Color('#aaaeff')
    };
    shader.uniforms.uHeight = {
        value: uHeight
    };

    shader.vertexShader = shader.vertexShader.replace("#include <common>", `
        #include <common>
        varying vec3 vPosition;
    `);

    shader.vertexShader = shader.vertexShader.replace("#include <begin_vertex>", `
        #include <begin_vertex>
        vPosition = position;
    `);

    shader.fragmentShader = shader.fragmentShader.replace("#include <common>", `
        #include <common>

        uniform vec3 uTopColor;
        uniform float uHeight;
        varying vec3 vPosition;
    `);

    shader.fragmentShader = shader.fragmentShader.replace("//#end#", `
        vec4 distGradColor = gl_FragColor;

        // 设置混合的百分比
        // 因为uHeight是最高和最低的差值，vPosition.y是有正有负的，
        // 比如最高+100，最低-100，所以要有下面的公式将范围限制在[0, 1]
        float gradMix = (vPosition.y + uHeight / 2.0) / uHeight;
        // 计算出混合颜色
        vec3 gradMixColor = mix(distGradColor.xyz, uTopColor, gradMix);
        gl_FragColor = vec4(gradMixColor, 1);

        //#end#
    `)
}

// 添加建筑材质光波扩散特效
export function addSpread(shader, center = new THREE.Vector2(0, 0)) {
    // 设置扩散的中心点
    shader.uniforms.uSpreadCenter = { value: center };
    // 扩散的时间
    shader.uniforms.uSpreadTime = { value: -2000 };
    // 设置条带的宽度
    shader.uniforms.uSpreadWidth = { value: 40 };

    shader.fragmentShader = shader.fragmentShader.replace("#include <common>", `
        #include <common>

        uniform vec2 uSpreadCenter;
        uniform float uSpreadTime;
        uniform float uSpreadWidth;
    `)

    shader.fragmentShader = shader.fragmentShader.replace("//#end#", `
        float spreadRadius = distance(vPosition.xz, uSpreadCenter);
        // 扩散范围的函数(y = -x^2 + b 抛物线)
        float spreadIndex = -(spreadRadius - uSpreadTime) * (spreadRadius - uSpreadTime) + uSpreadWidth;
    
        // 白色的抛物线曲线往外扩散
        if(spreadIndex > 0.0) {
            gl_FragColor = mix(gl_FragColor, vec4(1, 1, 1, 1), spreadIndex / uSpreadWidth);
        }

        //#end#
    `)

    // 设置uSpreadTime循环在3秒内从-2000到800
    gsap.to(shader.uniforms.uSpreadTime, {
        value: 800,
        duration: 3,
        ease: "none",
        repeat: -1
    })
}

export function addLightLine(shader) {
    // 扩散的时间
    shader.uniforms.uLightLineTime = { value: -1500 };
    // 设置条带的宽度
    shader.uniforms.uLightLineWidth = { value: 200 };

    shader.fragmentShader = shader.fragmentShader.replace("#include <common>", `
        #include <common>

        uniform float uLightLineTime;
        uniform float uLightLineWidth;
    `)

    shader.fragmentShader = shader.fragmentShader.replace("//#end#", `
        float LightLineMix = -(vPosition.x + vPosition.z - uLightLineTime) * (vPosition.x + vPosition.z - uLightLineTime) + uLightLineWidth;

        if(LightLineMix > 0.0) {
            gl_FragColor = mix(gl_FragColor, vec4(0.8, 1.0, 1.0, 1), LightLineMix / uLightLineWidth);
        }

        //#end#
    `)

    gsap.to(shader.uniforms.uLightLineTime, {
        value: 1500,
        duration: 5,
        ease: 'none',
        repeat: -1
    })
}

export function addToTopLine(shader) {
    // 扩散的时间
    shader.uniforms.uToTopTime = { value: 0 };
    // 设置条带的宽度
    shader.uniforms.uToTopWidth = { value: 40 };

    shader.fragmentShader = shader.fragmentShader.replace("#include <common>", `
        #include <common>

        uniform float uToTopTime;
        uniform float uToTopWidth;
    `)

    shader.fragmentShader = shader.fragmentShader.replace("//#end#", `
        float ToTopMix = -(vPosition.y - uToTopTime) * (vPosition.y - uToTopTime) + uToTopWidth;

        if(ToTopMix > 0.0) {
            gl_FragColor = mix(gl_FragColor, vec4(0.8, 0.8, 1.0, 1), ToTopMix / uToTopWidth);
        }

        //#end#
    `)

    gsap.to(shader.uniforms.uToTopTime, {
        value: 500,
        duration: 3,
        ease: 'none',
        repeat: -1
    })
}